#deep seek编写
import os
import json
import tkinter as tk
from tkinter import ttk, scrolledtext, font, messagebox, simpledialog
import pygame
from pygame import mixer
import asyncio
from threading import Thread
import edge_tts
import time
import requests  # 新增

class IntegratedTextReader:
    def __init__(self, root):
        self.root = root
        self.root.title("集成文本阅读器")
        self.root.geometry("1200x800")
        self.root.minsize(1000, 700)
        
        # 初始化设置
        self.settings_file = "reader_settings.json"
        self.default_data_dir = "./reading_materials"
        self.settings = self.load_settings()
        
        # 初始化音频引擎
        mixer.init()
        mixer.music.set_volume(self.settings.get("volume", 0.7))
        # 启动时清理临时文件
        self._cleanup_temp_files()  # 新增：启动时清理临时文件
        # 状态变量
        self.is_playing = False
        self.is_paused = False
        self.current_file_index = 0
        self.play_mode = "list"
        self.files = []
        self.current_texts = ("", "", "")
        self.editing = False
        self.current_audio_file = None
        
        # 语音设置
        self.voice_mapping = {
            "en": "en-US-GuyNeural",
            "cn": "zh-CN-YunxiNeural"
        }
        
        # 创建必要目录
        os.makedirs(self.default_data_dir, exist_ok=True)
        
        # 构建UI
        self.setup_ui()
        self.refresh_file_list()
        self.deepseek_api_key = self.settings["ai"]["api_key"]  # 新增：在此处填入您的DeepSeek API key
        self.deepseek_api_url = "https://api.deepseek.com/v1/chat/completions"  # 根据实际API地址修改
        # 绑定快捷键
        self.root.bind("<F5>", lambda e: self.refresh_file_list())
        self.root.bind("<Control-s>", lambda e: self.save_current_file())
        self.root.bind("<space>", lambda e: self.toggle_pause() if self.is_playing else None)
        self.root.bind("<Escape>", lambda e: self.stop_playing() if self.is_playing else self.cancel_edit())
        # 注册退出时的清理函数
        self.root.protocol("WM_DELETE_WINDOW", self.on_exit)

    def setup_ui(self):
        """设置用户界面"""
        # 主布局
        main_paned = tk.PanedWindow(self.root, orient=tk.HORIZONTAL, sashwidth=8)
        main_paned.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 左侧控制面板
        self.control_frame = tk.Frame(main_paned, width=360)
        main_paned.add(self.control_frame)
        
        # 右侧内容面板
        content_frame = tk.Frame(main_paned)
        main_paned.add(content_frame)
        
        # 右侧顶部面板 (标题 + AI功能)
        top_right_frame = tk.Frame(content_frame)
        top_right_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 标题区
        title_frame = tk.LabelFrame(top_right_frame, text="标题", padx=10, pady=10)
        title_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
        
        title_font = font.Font(size=14, weight="bold")
        # self.title_text = tk.Text(title_frame, height=2, wrap=tk.WORD, 
        #                         font=title_font, padx=5, pady=5)
        # self.title_text.pack(fill=tk.X)
        
        # AI功能区
        ai_frame = tk.LabelFrame(top_right_frame, text="AI功能", padx=10, pady=10)
        ai_frame.pack(side=tk.LEFT, padx=(10, 0))
        
        tk.Button(ai_frame, text="🖋️ 生成英文", command=self.generate_english_text,
                bg="#e8f5e9", fg="#2e7d32", width=10).pack(fill=tk.X, pady=2)
        tk.Button(ai_frame, text="🔄 翻译中文", command=self.generate_chinese_translation,
                bg="#e3f2fd", fg="#1565c0", width=10).pack(fill=tk.X, pady=2)
        tk.Button(ai_frame, text="⚙️ 设置", command=self.show_settings_dialog,
                bg="#f3e5f5", width=10).pack(fill=tk.X, pady=2)

        # 文件操作区 (保留在左侧)
        file_ops_frame = tk.LabelFrame(self.control_frame, text="文件操作", padx=10, pady=10)
        file_ops_frame.pack(fill=tk.X, pady=(0, 10))
        
        tk.Button(file_ops_frame, text="🔄 刷新列表", command=self.refresh_file_list,
                 bg="#e3f2fd").pack(fill=tk.X, pady=2)
        tk.Button(file_ops_frame, text="📄 新建文章", command=self.create_new_file,
                 bg="#e8f5e9").pack(fill=tk.X, pady=2)
        tk.Button(file_ops_frame, text="📂 打开目录", command=self.open_data_dir,
                 bg="#fff8e1").pack(fill=tk.X, pady=2)

        # ... 保留原有的文件列表区、朗读控制区等代码不变 ...

        # 文件列表区
        list_frame = tk.LabelFrame(self.control_frame, text="文章列表", padx=10, pady=10)
        list_frame.pack(fill=tk.BOTH, expand=True)
        
        self.file_listbox = tk.Listbox(list_frame, selectmode=tk.SINGLE, font=("Arial", 11))
        self.file_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.file_listbox.bind("<<ListboxSelect>>", self.on_file_select)
        self.file_listbox.bind("<Double-Button-1>", lambda e: self.play_selected())
        
        # 添加右键菜单
        self.file_listbox.bind("<Button-3>", self.show_context_menu)  # 右键点击
        
        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.file_listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.file_listbox.yview)
        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.file_listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.file_listbox.yview)
        
        # 朗读控制区
        self.play_frame = tk.LabelFrame(self.control_frame, text="朗读控制", padx=10, pady=10)
        self.play_frame.pack(fill=tk.BOTH, expand=True, pady=(10, 0))  # 修改为填充整个空间
        
        self.language_var = tk.StringVar(value="en")
        tk.Radiobutton(self.play_frame, text="英语朗读", variable=self.language_var, 
                      value="en").pack(anchor=tk.W)
        tk.Radiobutton(self.play_frame, text="中文朗读", variable=self.language_var, 
                      value="cn").pack(anchor=tk.W)
        
        # 语速控制
        speed_frame = tk.Frame(self.play_frame)
        speed_frame.pack(fill=tk.X, pady=(5, 0))
        tk.Label(speed_frame, text="语速:").pack(side=tk.LEFT)
        self.speed_var = tk.DoubleVar(value=self.settings.get("speed", 1.0))
        self.speed_slider = tk.Scale(speed_frame, from_=0.5, to=2.0, resolution=0.1,
                                    orient=tk.HORIZONTAL, variable=self.speed_var)
        self.speed_slider.pack(fill=tk.X, expand=True)
        self.speed_slider.bind("<ButtonRelease-1>", self.on_speed_change)
        
        self.play_selected_btn = tk.Button(self.play_frame, text="▶️ 播放选中", command=self.play_selected, 
                 state=tk.DISABLED)
        self.play_selected_btn.pack(fill=tk.X, pady=2)
        
        self.play_all_btn = tk.Button(self.play_frame, text="🔁 播放全部", command=self.play_all, 
                 state=tk.DISABLED)
        self.play_all_btn.pack(fill=tk.X, pady=2)
        
        control_btns_frame = tk.Frame(self.play_frame)
        control_btns_frame.pack(fill=tk.X, pady=(10, 0), expand=True)
        
        self.control_btns = {
            "pause": tk.Button(control_btns_frame, text="⏸️ 暂停", command=self.toggle_pause),
            "stop": tk.Button(control_btns_frame, text="⏹️ 停止", command=self.stop_playing),
            "edit": tk.Button(control_btns_frame, text="✏️ 编辑", command=self.toggle_edit_mode),
            "save": tk.Button(control_btns_frame, text="💾 保存", command=self.save_current_file)
        }
        
        # 使用grid布局替代pack布局
        self.control_btns["pause"].grid(row=0, column=0, sticky=tk.EW, padx=2, pady=2)
        self.control_btns["stop"].grid(row=0, column=1, sticky=tk.EW, padx=2, pady=2)
        self.control_btns["edit"].grid(row=1, column=0, sticky=tk.EW, padx=2, pady=2)
        self.control_btns["save"].grid(row=1, column=1, sticky=tk.EW, padx=2, pady=2)
        
        # 配置列权重
        control_btns_frame.columnconfigure(0, weight=1)
        control_btns_frame.columnconfigure(1, weight=1)
        
        # 删除以下冲突的pack代码
        # for btn in self.control_btns.values():
        #     btn.pack(fill=tk.X, pady=2)
        
        # # 右侧内容面板
        # title_frame = tk.LabelFrame(content_frame, text="标题", padx=10, pady=10)
        # title_frame.pack(fill=tk.X)
        
        title_font = font.Font(size=14, weight="bold")
        self.title_text = tk.Text(title_frame, height=2, wrap=tk.WORD, 
                                font=title_font, padx=5, pady=5)
        self.title_text.pack(fill=tk.X)
        
        content_paned = tk.PanedWindow(content_frame, orient=tk.HORIZONTAL, sashwidth=8)
        content_paned.pack(fill=tk.BOTH, expand=True)
        
        # 英文内容区
        en_frame = tk.LabelFrame(content_paned, text="英文内容", padx=10, pady=10)
        content_paned.add(en_frame)
        
        self.en_text = scrolledtext.ScrolledText(en_frame, wrap=tk.WORD, 
                                               font=("Arial", 12), padx=5, pady=5)
        self.en_text.pack(fill=tk.BOTH, expand=True)
        
        # 中文内容区
        cn_frame = tk.LabelFrame(content_paned, text="中文内容", padx=10, pady=10)
        content_paned.add(cn_frame)
        
        self.cn_text = scrolledtext.ScrolledText(cn_frame, wrap=tk.WORD, 
                                               font=("Microsoft YaHei", 12), padx=5, pady=5)
        self.cn_text.pack(fill=tk.BOTH, expand=True)
        
        # 状态栏
        self.status_var = tk.StringVar(value="🟢 准备就绪")
        status_bar = tk.Label(self.root, textvariable=self.status_var, 
                             bd=1, relief=tk.SUNKEN, anchor=tk.W, padx=10, pady=5)
        status_bar.pack(fill=tk.X, side=tk.BOTTOM, ipady=8)
    
    def on_exit(self):
        """程序退出时的清理操作"""
        # 停止当前播放
        if self.is_playing or self.is_paused:
            self.stop_playing()

        # 清理临时文件
        self._cleanup_temp_files()

        # 关闭窗口
        self.root.destroy()

    def show_settings_dialog(self):
        """显示设置对话框"""
        dialog = tk.Toplevel(self.root)
        dialog.title("AI生成设置")
        dialog.geometry("500x500")
        dialog.resizable(False, False)
        
        # 主框架
        main_frame = tk.Frame(dialog)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 确保设置中有ai字段
        if "ai" not in self.settings:
            self.settings["ai"] = {
                "temperature": 0.7,
                "max_tokens": 500,
                "api_key": self.deepseek_api_key,
                "english_prompt": "根据描述给我写一段英语美文段落...",
                "chinese_prompt": "将以下英文段落翻译成中文..."
            }
        
        # 创建滚动条
        canvas = tk.Canvas(main_frame)
        scrollbar = ttk.Scrollbar(main_frame, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 温度设置
        tk.Label(scrollable_frame, text="生成温度 (0.1-1.0):").pack(pady=(5, 0), anchor="w")
        self.temp_var = tk.DoubleVar(value=self.settings["ai"]["temperature"])
        tk.Scale(scrollable_frame, from_=0.1, to=1.0, resolution=0.1, orient=tk.HORIZONTAL,
                variable=self.temp_var).pack(fill=tk.X, pady=5)
        
        # 生成长度设置
        tk.Label(scrollable_frame, text="最大生成长度:").pack(pady=(5, 0), anchor="w")
        self.max_tokens_var = tk.IntVar(value=self.settings["ai"]["max_tokens"])
        tk.Entry(scrollable_frame, textvariable=self.max_tokens_var).pack(fill=tk.X, pady=5)
        
        # API Key设置
        tk.Label(scrollable_frame, text="DeepSeek API Key:").pack(pady=(5, 0), anchor="w")
        self.api_key_var = tk.StringVar(value=self.settings["ai"]["api_key"])
        tk.Entry(scrollable_frame, textvariable=self.api_key_var, show="*").pack(fill=tk.X, pady=5)
        
        # 英文Prompt设置
        tk.Label(scrollable_frame, text="英文生成Prompt:").pack(pady=(5, 0), anchor="w")
        self.english_prompt_var = tk.StringVar(value=self.settings["ai"]["english_prompt"])
        self.english_prompt_text = tk.Text(scrollable_frame, height=5, wrap=tk.WORD)
        self.english_prompt_text.insert("1.0", self.english_prompt_var.get())
        self.english_prompt_text.pack(fill=tk.X, pady=5)
        
        # 中文Prompt设置
        tk.Label(scrollable_frame, text="中文翻译Prompt:").pack(pady=(5, 0), anchor="w")
        self.chinese_prompt_var = tk.StringVar(value=self.settings["ai"]["chinese_prompt"])
        self.chinese_prompt_text = tk.Text(scrollable_frame, height=5, wrap=tk.WORD)
        self.chinese_prompt_text.insert("1.0", self.chinese_prompt_var.get())
        self.chinese_prompt_text.pack(fill=tk.X, pady=5)
        
        # 保存按钮
        save_btn = tk.Button(scrollable_frame, text="保存设置", command=lambda: self.save_ai_settings(dialog),
                bg="#4caf50", fg="white")
        save_btn.pack(pady=10)
        
        # 绑定回车键保存
        dialog.bind("<Return>", lambda e: self.save_ai_settings(dialog))
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def _cleanup_temp_files(self):
        """清理所有临时音频文件"""
        temp_files = [f for f in os.listdir() if f.startswith('temp_') and f.endswith('.mp3')]
        for temp_file in temp_files:
            try:
                os.remove(temp_file)
                print(f"已删除临时文件: {temp_file}")
            except Exception as e:
                print(f"删除临时文件 {temp_file} 失败: {e} (可能仍在被占用)")
                # 如果文件被占用，稍后再试一次
                try:
                    time.sleep(0.5)
                    os.remove(temp_file)
                    print(f"重试删除成功: {temp_file}")
                except:
                    print(f"最终删除失败: {temp_file}")

    def on_speed_change(self, event=None):
        """语速改变时的回调函数"""
        self.settings["speed"] = self.speed_var.get()
        self.save_settings()
        self.status_var.set(f"语速已设置为: {self.speed_var.get():.1f}倍")
    
    def get_current_voice(self):
        """获取当前选择的语音和语速"""
        voice = self.voice_mapping.get(self.language_var.get(), "en-US-GuyNeural")
        rate = self.speed_var.get()

        # 确保语速在合理范围内
        rate = max(0.5, min(2.0, rate))

        # edge_tts使用的rate格式是"+20%"或"-20%"
        rate_percent = int((rate - 1.0) * 100)
        if rate_percent > 0:
            rate_str = f"+{rate_percent}%"
        elif rate_percent < 0:
            rate_str = f"{rate_percent}%"
        else:
            rate_str = "+0%"

        return voice, rate_str
    
    def load_settings(self):
        """加载设置，自动合并默认值和本地设置"""
        default_settings = {
            "volume": 0.7,
            "speed": 1.0,
            "ai": {
                "temperature": 0.7,
                "max_tokens": 500,
                "api_key": "your-deepseek-api-key",  # 默认值
                "english_prompt": "请根据标题'{title}'创作一篇500词左右的英语美文...",
                "chinese_prompt": "请将以下英文段落翻译成优雅的中文：\n{text}"
            }
        }
        
        try:
            if os.path.exists(self.settings_file):
                with open(self.settings_file, "r", encoding="utf-8") as f:
                    saved_settings = json.load(f)
                    # 合并默认设置和已保存设置
                    default_settings.update(saved_settings)
                    return default_settings
            else:
                self.save_settings(default_settings)
                return default_settings
        except Exception as e:
            print(f"加载设置出错: {e}")
            return default_settings

    def save_settings(self, settings=None):
        """保存设置到文件"""
        try:
            # 如果没有传入设置参数，则保存当前设置
            if settings is None:
                settings = {
                    "volume": mixer.music.get_volume(),
                    "speed": self.speed_var.get(),
                    "ai": self.settings.get("ai", {})  # 确保包含AI设置
                }
            
            with open(self.settings_file, "w", encoding="utf-8") as f:
                json.dump(settings, f, indent=4, ensure_ascii=False)
        except Exception as e:
            print(f"保存设置出错: {e}")
            self.status_var.set(f"❌ 保存设置失败: {e}")


    def call_deepseek_api(self, messages, temperature=None, max_tokens=None):
        """调用DeepSeek API的通用方法"""
        # 使用设置中的值或默认值
        ai_settings = self.settings.get("ai", {})
        temperature = temperature if temperature is not None else ai_settings.get("temperature", 0.7)
        max_tokens = max_tokens if max_tokens is not None else ai_settings.get("max_tokens", 500)
        
        headers = {
            "Authorization": f"Bearer {self.deepseek_api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": "deepseek-chat",
            "messages": messages,
            "temperature": temperature,
            "max_tokens": max_tokens
        }
        
        try:
            response = requests.post(
                self.deepseek_api_url,
                headers=headers,
                data=json.dumps(payload),
                timeout=30
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            raise Exception(f"API请求失败: {str(e)}")
        
    def toggle_edit_mode(self):
        """切换编辑模式"""
        self.editing = not self.editing
        
        if self.editing:
            # 进入编辑模式
            self.title_text.config(state=tk.NORMAL, bg="#fffde7")
            self.en_text.config(state=tk.NORMAL, bg="#fffde7")
            self.cn_text.config(state=tk.NORMAL, bg="#fffde7")
            self.control_btns["edit"].config(text="❌ 取消编辑", state=tk.NORMAL)  # 强制启用按钮
            self.control_btns["save"].config(state=tk.NORMAL)
            self.status_var.set("✏️ 编辑模式 - 按Ctrl+S保存或点击保存按钮")
        else:
            # 退出编辑模式
            self.title_text.config(state=tk.DISABLED, bg="white")
            self.en_text.config(state=tk.DISABLED, bg="white")
            self.cn_text.config(state=tk.DISABLED, bg="white")
            self.control_btns["edit"].config(text="✏️ 编辑")
            self.control_btns["save"].config(state=tk.DISABLED)
            self.status_var.set("🟢 浏览模式")
        
        self.update_ui_state()
    
    
    def cancel_edit(self):
        """取消编辑并恢复原内容"""
        if self.editing:
            self.toggle_edit_mode()
            self.on_file_select()  # 重新加载当前文件内容
    
    def save_current_file(self):
        """保存当前编辑的内容"""
        if not self.editing or not self.files:
            return
            
        title_path, en_path, cn_path = self.files[self.current_file_index]
        
        try:
            # 获取编辑后的内容
            title_content = self.title_text.get("1.0", tk.END).strip()
            en_content = self.en_text.get("1.0", tk.END).strip()
            cn_content = self.cn_text.get("1.0", tk.END).strip()
            
            # 保存到文件
            with open(title_path, "w", encoding="utf-8") as f:
                f.write(title_content)
            with open(en_path, "w", encoding="utf-8") as f:
                f.write(en_content)
            with open(cn_path, "w", encoding="utf-8") as f:
                f.write(cn_content)
            
            self.status_var.set("💾 保存成功!")
            self.toggle_edit_mode()  # 退出编辑模式
            
            # 更新列表显示名称
            base_name = os.path.basename(title_path).replace(".t.txt", "")
            new_base_name = "".join(c if c.isalnum() else "_" for c in title_content)[:50]
            if base_name != new_base_name:
                # 如果标题变化大，建议重命名文件
                if messagebox.askyesno("重命名", "标题已更改，是否重命名文件?"):
                    self.rename_current_file(new_base_name)
            
        except Exception as e:
            messagebox.showerror("保存错误", f"保存文件失败:\n{str(e)}")
            self.status_var.set(f"❌ 保存失败: {str(e)}")
    
    def generate_english_text(self):
        """根据标题生成英文美文"""
        if not self.editing:
            messagebox.showwarning("提示", "请先进入编辑模式")
            return
            
        title = self.title_text.get("1.0", tk.END).strip()
        if not title:
            messagebox.showwarning("提示", "请先在标题栏输入文章描述")
            return
            
        # 显示等待状态
        self.status_var.set("⏳ 正在生成英文美文...")
        self.root.update()
        
        # 在独立线程中执行API调用
        Thread(target=self._generate_english_thread, args=(title,), daemon=True).start()
    
    def _generate_english_thread(self, title):
        """生成英文的后台线程"""
        try:
            # 使用保存的prompt并插入标题
            prompt = self.settings["ai"]["english_prompt"].format(title=title)
            
            # 调用DeepSeek API
            response = self.call_deepseek_api(
                messages=[
                    {"role": "system", "content": "你是一位专业的英语作家，擅长创作文学性强的优美段落。"},
                    {"role": "user", "content": f"根据这个标题创作英文内容：{title}\n{prompt}"}
                ],
                temperature=self.settings["ai"]["temperature"],
                max_tokens=self.settings["ai"]["max_tokens"]
            )
            
            # 获取生成的文本
            generated_text = response['choices'][0]['message']['content'].strip()
            
            # 在主线程中更新UI
            self.root.after(0, lambda: self._update_english_text(generated_text))
            
        except Exception as e:
            # 修复lambda捕获异常变量
            self.root.after(0, lambda e=e: messagebox.showerror("生成错误", f"生成英文美文失败:\n{str(e)}"))
            self.root.after(0, lambda e=e: self.status_var.set(f"❌ 生成失败: {str(e)}"))
    
    def _update_english_text(self, text):
        """更新英文内容区"""
        self.en_text.config(state=tk.NORMAL)
        self.en_text.delete("1.0", tk.END)
        self.en_text.insert("1.0", text)
        self.status_var.set("✅ 英文美文生成完成！")

    def generate_chinese_translation(self):
        """将英文内容翻译成中文"""
        if not self.editing:
            messagebox.showwarning("提示", "请先进入编辑模式")
            return
            
        english_text = self.en_text.get("1.0", tk.END).strip()
        if not english_text:
            messagebox.showwarning("提示", "请先生成或输入英文内容")
            return
            
        # 显示等待状态
        self.status_var.set("⏳ 正在生成中文翻译...")
        self.root.update()
        
        # 在独立线程中执行API调用
        Thread(target=self._generate_chinese_thread, args=(english_text,), daemon=True).start()
    
    def _generate_chinese_thread(self, english_text):
        """生成中文翻译的后台线程"""
        try:
            # 使用保存的prompt并插入英文原文
            prompt = self.settings["ai"]["chinese_prompt"].format(text=english_text)
            
            # 调用DeepSeek API
            response = self.call_deepseek_api(
                messages=[
                    {"role": "system", "content": "你是一位专业的文学翻译家，擅长将英文美文翻译成优雅的中文。"},
                    {"role": "user", "content": f"请翻译以下英文内容：\n{english_text}\n{prompt}"}
                ],
                temperature=self.settings["ai"]["temperature"],
                max_tokens=self.settings["ai"]["max_tokens"]
            )
            
            # 获取翻译的文本
            translated_text = response['choices'][0]['message']['content'].strip()
            
            # 在主线程中更新UI
            self.root.after(0, lambda: self._update_chinese_text(translated_text))
            
        except Exception as e:
            # 修复lambda捕获异常变量
            self.root.after(0, lambda e=e: messagebox.showerror("翻译错误", f"生成中文翻译失败:\n{str(e)}"))
            self.root.after(0, lambda e=e: self.status_var.set(f"❌ 翻译失败: {str(e)}"))

    def _update_chinese_text(self, text):
        """更新中文内容区"""
        self.cn_text.config(state=tk.NORMAL)
        self.cn_text.delete("1.0", tk.END)
        self.cn_text.insert("1.0", text)
        self.status_var.set("✅ 中文翻译生成完成！")

    def save_ai_settings(self, dialog):
        """保存AI设置到配置文件"""
        try:
            # 更新AI设置
            self.settings["ai"] = {
                "temperature": float(self.temp_var.get()),
                "max_tokens": int(self.max_tokens_var.get()),
                "api_key": self.api_key_var.get(),
                "english_prompt": self.english_prompt_text.get("1.0", tk.END).strip(),
                "chinese_prompt": self.chinese_prompt_text.get("1.0", tk.END).strip()
            }
            
            # 更新当前API key
            self.deepseek_api_key = self.api_key_var.get()
            
            # 保存设置
            if self.save_settings():
                dialog.destroy()
                self.status_var.set("✅ AI设置已保存")
            else:
                self.status_var.set("❌ 保存AI设置失败")
                
        except ValueError as e:
            self.status_var.set(f"❌ 无效的数值设置: {str(e)}")
        except Exception as e:
            self.status_var.set(f"❌ 保存AI设置失败: {str(e)}")

    def update_ui_state(self):
        """根据当前状态更新UI元素"""
        has_files = len(self.files) > 0
        has_selection = bool(self.file_listbox.curselection())
        
        # 更新编辑按钮状态（新增逻辑）
        edit_btn_state = tk.NORMAL if (has_selection or self.editing) else tk.DISABLED
        self.control_btns["edit"].config(state=edit_btn_state)
        
        # 原有其他按钮状态控制代码保持不变...

    def rename_current_file(self, new_base_name):
        """重命名当前文件组"""
        if not self.files:
            return
            
        old_title, old_en, old_cn = self.files[self.current_file_index]
        dir_name = os.path.dirname(old_title)
        
        try:
            # 新文件名
            new_title = os.path.join(dir_name, f"{new_base_name}.t.txt")
            new_en = os.path.join(dir_name, f"{new_base_name}.e.txt")
            new_cn = os.path.join(dir_name, f"{new_base_name}.c.txt")
            
            # 重命名文件
            os.rename(old_title, new_title)
            os.rename(old_en, new_en)
            os.rename(old_cn, new_cn)
            
            # 更新文件列表
            self.files[self.current_file_index] = (new_title, new_en, new_cn)
            self.file_listbox.delete(self.current_file_index)
            self.file_listbox.insert(self.current_file_index, new_base_name)
            self.file_listbox.selection_set(self.current_file_index)
            
            self.status_var.set("✅ 文件重命名成功!")
        except Exception as e:
            messagebox.showerror("重命名错误", f"重命名文件失败:\n{str(e)}")
            self.status_var.set(f"❌ 重命名失败: {str(e)}")
    
    def update_ui_state(self):
        """根据当前状态更新UI元素"""
        has_files = len(self.files) > 0
        has_selection = bool(self.file_listbox.curselection())
        
        # 更新按钮状态
        self.control_btns["pause"].config(
            text="⏸️ 暂停" if not self.is_paused else "▶️ 继续",
            state=tk.NORMAL if self.is_playing else tk.DISABLED
        )
        self.control_btns["stop"].config(
            state=tk.NORMAL if self.is_playing else tk.DISABLED
        )
        self.control_btns["edit"].config(
            state=tk.NORMAL if has_selection and not self.is_playing else tk.DISABLED
        )
        
        # 更新播放按钮
        self.play_selected_btn.config(state=tk.NORMAL if has_selection else tk.DISABLED)
        self.play_all_btn.config(state=tk.NORMAL if has_files else tk.DISABLED)
    
    def on_file_select(self, event=None):
        """当选择文件时触发"""
        if not self.file_listbox.curselection():
            return
            
        self.current_file_index = self.file_listbox.curselection()[0]
        title_path, en_path, cn_path = self.files[self.current_file_index]
        
        try:
            with open(title_path, "r", encoding="utf-8") as f:
                title = f.read()
            with open(en_path, "r", encoding="utf-8") as f:
                en_content = f.read()
            with open(cn_path, "r", encoding="utf-8") as f:
                cn_content = f.read()
                
            self.current_texts = (title, en_content, cn_content)
            self.update_text_display(title, en_content, cn_content)
            self.status_var.set(f"📄 已加载: {os.path.basename(title_path)}")
        except Exception as e:
            self.status_var.set(f"❌ 加载文件出错: {str(e)}")
        
        self.update_ui_state()
    
    def update_text_display(self, title, en_text, cn_text):
        """更新文本显示区域"""
        # 更新标题
        self.title_text.config(state=tk.NORMAL)
        self.title_text.delete("1.0", tk.END)
        self.title_text.insert("1.0", title)
        self.title_text.config(state=tk.DISABLED if not self.editing else tk.NORMAL)
        
        # 更新英文内容
        self.en_text.config(state=tk.NORMAL)
        self.en_text.delete("1.0", tk.END)
        self.en_text.insert("1.0", en_text)
        self.en_text.config(state=tk.DISABLED if not self.editing else tk.NORMAL)
        
        # 更新中文内容
        self.cn_text.config(state=tk.NORMAL)
        self.cn_text.delete("1.0", tk.END)
        self.cn_text.insert("1.0", cn_text)
        self.cn_text.config(state=tk.DISABLED if not self.editing else tk.NORMAL)
        
        # 滚动到顶部
        for text_widget in [self.title_text, self.en_text, self.cn_text]:
            text_widget.see("1.0")
    
    def refresh_file_list(self):
        """刷新文件列表"""
        self.files = []
        self.file_listbox.delete(0, tk.END)
        
        try:
            files = os.listdir(self.default_data_dir)
            title_files = sorted([f for f in files if f.endswith('.t.txt')])
            
            for title_file in title_files:
                base_name = title_file.replace('.t.txt', '')
                en_file = base_name + '.e.txt'
                cn_file = base_name + '.c.txt'
                
                if en_file in files and cn_file in files:
                    self.files.append((
                        os.path.join(self.default_data_dir, title_file),
                        os.path.join(self.default_data_dir, en_file),
                        os.path.join(self.default_data_dir, cn_file)
                    ))
                    display_name = base_name.replace("_", " ").title()
                    self.file_listbox.insert(tk.END, display_name)
            
            status = f"📂 已加载 {len(self.files)} 篇文章" if self.files else "📂 目录为空"
            self.status_var.set(status)
        except Exception as e:
            self.status_var.set(f"❌ 读取目录出错: {str(e)}")
        
        self.update_ui_state()
    def _prepare_audio_file(self):
        """准备当前文件的音频临时文件"""
        title_path, en_path, cn_path = self.files[self.current_file_index]
        temp_file = f"temp_{os.path.basename(title_path)}.mp3"
        
        try:
            # 确定朗读内容
            if self.language_var.get() == "en":
                with open(en_path, "r", encoding="utf-8") as f:
                    text = f.read()
            else:
                with open(cn_path, "r", encoding="utf-8") as f:
                    text = f.read()

            # 获取语音参数
            voice, rate = self.get_current_voice()
            
            # 生成音频文件
            communicate = edge_tts.Communicate(text, voice, rate=rate)
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(communicate.save(temp_file))
            loop.close()
            
            self.current_audio_file = temp_file
            return True
            
        except Exception as e:
            self.root.after(0, lambda e=e: self.status_var.set(f"❌ 准备音频失败: {str(e)}"))
            return False
    def create_new_file(self):
        """创建新的文章组"""
        title = simpledialog.askstring("新建文章", "请输入文章标题:", parent=self.root)
        if not title:
            return
            
        base_name = "".join(c if c.isalnum() else "_" for c in title)[:50]
        filename = f"{base_name}_{int(time.time())}"
        
        try:
            # 创建文件路径
            title_path = os.path.join(self.default_data_dir, f"{filename}.t.txt")
            en_path = os.path.join(self.default_data_dir, f"{filename}.e.txt")
            cn_path = os.path.join(self.default_data_dir, f"{filename}.c.txt")
            
            # 写入初始内容
            with open(title_path, "w", encoding="utf-8") as f:
                f.write(title)
            with open(en_path, "w", encoding="utf-8") as f:
                f.write("Enter English content here...")
            with open(cn_path, "w", encoding="utf-8") as f:
                f.write("在此输入中文内容...")
            
            # 刷新并选中新文件
            self.refresh_file_list()
            self.file_listbox.selection_set(tk.END)
            self.file_listbox.see(tk.END)
            self.on_file_select()
            
            # 自动进入编辑模式
            self.toggle_edit_mode()
            
            self.status_var.set(f"✅ 已创建新文章: {title}")
        except Exception as e:
            self.status_var.set(f"❌ 创建文件失败: {str(e)}")
    
    def open_data_dir(self):
        """打开数据目录"""
        try:
            if os.name == "nt":
                os.startfile(self.default_data_dir)
            elif os.name == "posix":
                if os.uname().sysname == "Darwin":
                    os.system(f'open "{self.default_data_dir}"')
                else:
                    os.system(f'xdg-open "{self.default_data_dir}"')
            self.status_var.set(f"📂 已打开目录: {self.default_data_dir}")
        except Exception as e:
            self.status_var.set(f"❌ 无法打开目录: {str(e)}")

    def play_current_file(self):
        """播放当前选中的文件"""
        # 如果正在编辑，提示保存
        if self.editing:
            if not messagebox.askyesno("保存提示", "当前正在编辑，是否先保存内容?"):
                return
            self.save_current_file()

        # 停止当前播放（如果有）
        if self.is_playing or self.is_paused:
            mixer.music.stop()

        # 重置播放状态
        self.is_playing = True
        self.is_paused = False
        self.update_ui_state()

        title_path = self.files[self.current_file_index][0]
        self.status_var.set(f"🔊 正在朗读: {os.path.basename(title_path)}...")

        # 在独立线程中播放
        Thread(target=self._play_audio_thread, daemon=True).start()

    def _play_audio_thread(self):
        """音频播放线程"""
        title_path, en_path, cn_path = self.files[self.current_file_index]
        temp_file = "temp_audio.mp3"
        
        try:
            # 确定朗读内容和语音
            if self.language_var.get() == "en":
                with open(en_path, "r", encoding="utf-8") as f:
                    text = f.read()
            else:
                with open(cn_path, "r", encoding="utf-8") as f:
                    text = f.read()
            
            # 修改这部分代码
            voice, rate = self.get_current_voice()
            
            # 生成临时音频文件
            communicate = edge_tts.Communicate(text, voice, rate=rate)
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(communicate.save(temp_file))
            loop.close()
            
            # 播放音频
            mixer.music.load(temp_file)
            mixer.music.play()
            
            # 播放状态监控循环
            while self.is_playing:
                if self.is_paused:
                    pygame.time.Clock().tick(10)
                    continue
                    
                if not mixer.music.get_busy():
                    # 当前文件播放完成
                    if self.play_mode == "list":
                        self.current_file_index += 1
                        if self.current_file_index >= len(self.files):
                            self.current_file_index = 0
                    
                    if self.current_file_index < len(self.files):
                        self.root.after(0, self.play_current_file)
                    break
                    
                pygame.time.Clock().tick(10)
                
        except Exception as e:
            # 修复lambda捕获异常变量
            self.root.after(0, lambda e=e: self.status_var.set(f"❌ 播放错误: {str(e)}"))
        finally:
            if os.path.exists(temp_file):
                try:
                    os.remove(temp_file)
                except:
                    pass
            self.root.after(0, self._playback_finished)

    def play_selected(self):
        """播放选中的文章"""
        if not self.file_listbox.curselection():
            return
            
        # 停止当前播放并清理
        if self.is_playing or self.is_paused:
            self.stop_playing()
        
        # 设置新的播放文件
        self.current_file_index = self.file_listbox.curselection()[0]
        self._start_playback()

    def play_all(self):
        """播放全部文章"""
        if not self.files:
            return
            
        # 停止当前播放并清理
        if self.is_playing or self.is_paused:
            self.stop_playing()
            
        self.current_file_index = 0
        self._start_playback()
    
    def toggle_pause(self):
        """暂停/继续播放"""
        if not self.is_playing:
            return
            
        if self.is_paused:
            # 继续播放
            mixer.music.unpause()
            self.is_paused = False
            self.status_var.set(f"🔊 正在朗读: {os.path.basename(self.files[self.current_file_index][0])}...")
            self.control_btns["pause"].config(text="⏸️ 暂停")
        else:
            # 暂停播放
            mixer.music.pause()
            self.is_paused = True
            self.status_var.set("⏸️ 播放已暂停")
            self.control_btns["pause"].config(text="▶️ 继续")
        
        self.update_ui_state()
    
    def stop_playing(self):
        """停止播放"""
        self.is_playing = False
        self.is_paused = False
        mixer.music.stop()
        self._cleanup_playback()
        self.status_var.set("⏹️ 播放已停止")
        self.update_ui_state()
    
    def _start_playback(self):
        """开始播放"""
        # 如果正在编辑，提示保存
        if self.editing:
            if not messagebox.askyesno("保存提示", "当前正在编辑，是否先保存内容?"):
                return
            self.save_current_file()

        # 初始化播放状态
        self.is_playing = True
        self.is_paused = False
        self.update_ui_state()

        title_path = self.files[self.current_file_index][0]
        self.status_var.set(f"🔊 正在准备: {os.path.basename(title_path)}...")

        # 在独立线程中播放
        Thread(target=self._playback_thread, daemon=True).start()
    
    def _playback_thread(self):
        """全新的播放控制线程"""
        try:
            while self.is_playing and self.current_file_index < len(self.files):
                # 准备当前文件音频
                if not self._prepare_audio_file():
                    break
                
                # 开始播放
                mixer.music.load(self.current_audio_file)
                mixer.music.play()
                self.root.after(0, lambda: self.status_var.set(
                    f"🔊 正在朗读: {os.path.basename(self.files[self.current_file_index][0])}..."
                ))
                
                # 播放监控循环
                while self.is_playing and mixer.music.get_busy():
                    if self.is_paused:
                        mixer.music.pause()
                        while self.is_paused and self.is_playing:
                            time.sleep(0.1)
                        if self.is_playing and not self.is_paused:
                            mixer.music.unpause()
                    time.sleep(0.1)
                
                # 清理当前文件
                self._remove_temp_file()
                
                # 确定下一个文件
                if self.play_mode == "list":
                    self.current_file_index += 1
                else:
                    break
                
                # 单文件循环播放
                if self.current_file_index >= len(self.files):
                    self.current_file_index = 0 if self.play_mode == "list" else -1

        except Exception as e:
            self.root.after(0, lambda e=e: self.status_var.set(f"❌ 播放错误: {str(e)}"))
        finally:
            # 确保状态重置
            self.is_playing = False
            self.is_paused = False
            self._remove_temp_file()
            self.root.after(0, self._playback_finished)

    def _playback_finished(self):
        """播放完成后的统一清理"""
        self._remove_temp_file()
        self.update_ui_state()
        self.status_var.set("🟢 播放完成" if self.files else "🟢 准备就绪")

    def _start_playback(self):
        """重构后的播放启动方法"""
        if self.editing and not messagebox.askyesno("保存提示", "当前正在编辑，是否先保存内容?"):
            return
        
        # 初始化播放状态
        self.is_playing = True
        self.is_paused = False
        self.update_ui_state()
        
        # 启动独立播放线程
        Thread(target=self._playback_thread, daemon=True).start()

    def stop_playing(self):
        """增强的停止方法"""
        self.is_playing = False
        self.is_paused = False
        mixer.music.stop()
        self._playback_finished()
        self.status_var.set("⏹️ 播放已停止")

    def toggle_pause(self):
        """改进的暂停/继续逻辑"""
        if not self.is_playing:
            return
            
        self.is_paused = not self.is_paused
        self.control_btns["pause"].config(
            text="▶️ 继续" if self.is_paused else "⏸️ 暂停"
        )
        self.status_var.set("⏸️ 播放已暂停" if self.is_paused else 
            f"🔊 正在朗读: {os.path.basename(self.files[self.current_file_index][0])}...")

    def _cleanup_playback(self):
        """清理播放状态和资源"""
        self._remove_temp_file()
        self.update_ui_state()
    
    def _remove_temp_file(self):
        """删除临时音频文件"""
        if self.current_audio_file and os.path.exists(self.current_audio_file):
            try:
                os.remove(self.current_audio_file)
                self.current_audio_file = None
            except Exception as e:
                print(f"删除临时文件出错: {e}")
        pass
    def show_context_menu(self, event):
        """显示右键菜单"""
        # 获取点击位置的项目
        index = self.file_listbox.nearest(event.y)
        if index >= 0:
            self.file_listbox.selection_clear(0, tk.END)
            self.file_listbox.selection_set(index)
            self.current_file_index = index

            # 创建菜单
            menu = tk.Menu(self.root, tearoff=0)
            menu.add_command(label="删除文章", command=self.delete_selected_file)
            menu.add_separator()
            menu.add_command(label="取消", command=lambda: menu.unpost())

            # 显示菜单
            try:
                menu.tk_popup(event.x_root, event.y_root)
            finally:
                menu.grab_release()

    def delete_selected_file(self):
        """删除选中的文章"""
        if not self.files or self.current_file_index >= len(self.files):
            return

        # 获取要删除的文件组
        title_path, en_path, cn_path = self.files[self.current_file_index]
        file_name = os.path.basename(title_path).replace(".t.txt", "")

        # 确认对话框
        if not messagebox.askyesno(
            "确认删除",
            f"确定要删除文章 '{file_name}' 吗?\n\n"
            "这将永久删除以下文件:\n"
            f"- {os.path.basename(title_path)}\n"
            f"- {os.path.basename(en_path)}\n"
            f"- {os.path.basename(cn_path)}",
            parent=self.root
        ):
            return

        try:
            # 停止当前播放（如果正在播放该文件）
            if self.is_playing and self.current_file_index == self.file_listbox.curselection()[0]:
                self.stop_playing()

            # 删除文件
            os.remove(title_path)
            os.remove(en_path)
            os.remove(cn_path)

            # 更新文件列表
            self.refresh_file_list()
            self.status_var.set(f"✅ 已删除文章: {file_name}")

        except Exception as e:
            messagebox.showerror("删除错误", f"删除文件失败:\n{str(e)}")
            self.status_var.set(f"❌ 删除失败: {str(e)}")
    
if __name__ == "__main__":
    pygame.init()
    root = tk.Tk()
    app = IntegratedTextReader(root)
    root.mainloop()